package com.liam.chinesevietnamesecorpus.service.impl;

import com.liam.chinesevietnamesecorpus.common.exception.ServiceException;
import com.liam.chinesevietnamesecorpus.service.EmailService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.security.SecureRandom;
import java.util.concurrent.TimeUnit;

/**
 * 邮箱服务实现类
 * 
 * @author Liam
 */
@Slf4j
@Service
public class EmailServiceImpl implements EmailService {

    @Autowired(required = false)
    private JavaMailSender mailSender;

    @Autowired(required = false)
    private StringRedisTemplate redisTemplate;

    @Value("${spring.mail.username:admin@example.com}")
    private String fromEmail;

    @Value("${verification.email.expire-minutes:5}")
    private int expireMinutes;

    @Value("${app.name:Chinese Vietnamese Corpus}")
    private String appName;

    private final SecureRandom random = new SecureRandom();

    @Override
    public void sendVerificationCode(String email, String type) {
        // 生成6位随机验证码
        String code = generateVerificationCode();
        
        log.info("=== 邮箱验证码 ===");
        log.info("邮箱: {}", email);
        log.info("类型: {}", type);
        log.info("验证码: {}", code);
        log.info("有效期: {} 分钟", expireMinutes);
        log.info("==================");
        
        // 检查Redis是否可用
        if (redisTemplate == null) {
            log.warn("Redis不可用，无法存储验证码");
            throw new ServiceException("系统配置错误，请联系管理员");
        }

        try {
            // 检查是否频繁发送
            String sendKey = "email:send:" + email + ":" + type;
            if (Boolean.TRUE.equals(redisTemplate.hasKey(sendKey))) {
                throw new ServiceException("验证码发送过于频繁，请稍后再试");
            }

            // 保存验证码到Redis，有效期5分钟
            String codeKey = "email:code:" + email + ":" + type;
            redisTemplate.opsForValue().set(codeKey, code, expireMinutes, TimeUnit.MINUTES);

            // 设置发送限制，1分钟内不能重复发送
            redisTemplate.opsForValue().set(sendKey, "1", 1, TimeUnit.MINUTES);

            log.info("验证码已存储到Redis：email={}, type={}, code={}", email, type, code);

            // 如果邮件服务可用，则发送邮件
            if (mailSender != null) {
                try {
                    SimpleMailMessage message = new SimpleMailMessage();
                    message.setFrom(fromEmail);
                    message.setTo(email);
                    message.setSubject(getEmailSubject(type));
                    message.setText(getEmailContent(code, type));

                    mailSender.send(message);
                    log.info("验证码邮件发送成功：email={}, type={}", email, type);

                } catch (Exception e) {
                    // 邮件发送失败，但验证码已存储，不影响验证
                    log.error("验证码邮件发送失败：email={}, type={}", email, type, e);
                    log.info("验证码已存储，可通过日志查看：{}", code);
                }
            } else {
                log.warn("邮件服务不可用，验证码仅存储在Redis中");
            }

        } catch (Exception e) {
            log.error("发送验证码过程中发生异常：email={}, type={}", email, type, e);
            throw new ServiceException("验证码发送失败，请稍后再试");
        }
    }

    @Override
    public boolean verifyCode(String email, String code, String type) {
        if (!StringUtils.hasText(email) || !StringUtils.hasText(code) || !StringUtils.hasText(type)) {
            return false;
        }

        // 检查Redis是否可用
        if (redisTemplate == null) {
            log.warn("Redis不可用，跳过验证码验证：email={}, type={}, code={}", email, type, code);
            return true; // 开发环境临时跳过
        }

        try {
            String codeKey = "email:code:" + email + ":" + type;
            String storedCode = redisTemplate.opsForValue().get(codeKey);

            if (storedCode != null && storedCode.equals(code)) {
                // 验证成功后删除验证码
                redisTemplate.delete(codeKey);
                log.info("邮箱验证码验证成功：email={}, type={}", email, type);
                return true;
            }

            log.warn("邮箱验证码验证失败：email={}, type={}, code={}, storedCode={}", email, type, code, storedCode);
            return false;
        } catch (Exception e) {
            log.error("验证码验证过程中发生异常：email={}, type={}, code={}", email, type, code, e);
            return false;
        }
    }

    /**
     * 生成6位随机验证码
     */
    private String generateVerificationCode() {
        return String.format("%06d", random.nextInt(1000000));
    }

    /**
     * 获取邮件主题
     */
    private String getEmailSubject(String type) {
        return switch (type) {
            case "register" -> String.format("[%s] 注册验证码", appName);
            case "reset" -> String.format("[%s] 密码重置验证码", appName);
            default -> String.format("[%s] 验证码", appName);
        };
    }

    /**
     * 获取邮件内容
     */
    private String getEmailContent(String code, String type) {
        String operation = switch (type) {
            case "register" -> "注册账户";
            case "reset" -> "重置密码";
            default -> "验证身份";
        };

        return String.format("""
            您好！
            
            您正在进行%s操作，验证码是：%s
            
            验证码有效期为%d分钟，请尽快完成操作。
            如果这不是您的操作，请忽略此邮件。
            
            %s
            """, operation, code, expireMinutes, appName);
    }
}
